/*
iverilog -g2012 -o "d:/Git_data/FPGA_DigitalIDE/vending_machine_v2/prj/simulation/icarus/out1.vvp" -s vending_machine_mix1_tb -I "d:/Git_data/FPGA_DigitalIDE/vending_machine_v2/user/src/" "d:/Git_data/FPGA_DigitalIDE/vending_machine_v2/user/sim/vending_machine_mix1_tb.v"
vvp "d:/Git_data/FPGA_DigitalIDE/vending_machine_v2/prj/simulation/icarus/out1.vvp"
 
iverilog -g2012 -o "/Users/tan_haozun/Documents/Git_data_mac/FPGA_DigitalIDE/vending_machine_v2/prj/simulation/icarus/out1.vvp" -s vending_machine_mix1_tb -I "/Users/tan_haozun/Documents/Git_data_mac/FPGA_DigitalIDE/vending_machine_v2/user/src/" "/Users/tan_haozun/Documents/Git_data_mac/FPGA_DigitalIDE/vending_machine_v2/user/sim/vending_machine_mix1_tb.v"
vvp "/Users/tan_haozun/Documents/Git_data_mac/FPGA_DigitalIDE/vending_machine_v2/prj/simulation/icarus/out1.vvp"
*/

`timescale 1ns / 1ps

//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2024/12/16 09:29:59
// Design Name:
// Module Name: vending_machine
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////


// module vending_machine (
//     input wire clk,           // 时钟信号
//     input wire rst,           // 复位信号
//     input wire [2:0] coin,    // 投币金额 (001: 1元, 010: 2元, 100: 5元)
//     input wire [1:0] sel,     // 商品选择 (00: 无选择, 01: A, 10: B, 11: C)
//     input wire goods_num_query, // 库存查询信号
//     output reg dispense,      // 商品输出信号
//     output reg [3:0] change,  // 找零金额
//     output reg low_balance,   // 余额不足信号
//     output reg [3:0] balance, // 当前余额
//     output reg [3:0] num_goods_disp // 当前查询的商品库存
// );

//     // ---------------------------------------------
//     // 商品价格和初始库存定义
//     parameter PRICE_A = 4;  // 商品A价格：4元
//     parameter PRICE_B = 6;  // 商品B价格：6元
//     parameter PRICE_C = 8;  // 商品C价格：8元

//     reg [3:0] num_goods[2:0]; // 商品库存数组：A、B、C的库存数量

//     // ---------------------------------------------
//     // 状态定义
//     parameter IDLE     = 3'b000;
//     parameter COIN     = 3'b001;
//     parameter SELECT   = 3'b010;
//     parameter DISPENSE = 3'b011;
//     parameter FINISH   = 3'b100;

//     reg [2:0] current_state, next_state; // 当前状态和下一状态

//     // ---------------------------------------------
//     // 状态转移逻辑
//     always @(posedge clk or posedge rst) begin
//         if (rst) begin
//             current_state <= IDLE;
//             balance <= 0;
//             num_goods[0] <= 4; // 商品A库存初始化
//             num_goods[1] <= 5; // 商品B库存初始化
//             num_goods[2] <= 3; // 商品C库存初始化
//         end else begin
//             current_state <= next_state;
//         end
//     end

//     // ---------------------------------------------
//     // 状态机：下一状态逻辑与输出逻辑
//     always @(*) begin
//         // 默认信号重置
//         next_state = current_state;
//         dispense = 0;
//         change = 0;
//         low_balance = 0;

//         case (current_state)
//             IDLE: begin
//                 if (coin > 0) begin
//                     next_state = COIN;
//                 end
//             end

//             COIN: begin
//                 if (coin == 3'b001) balance = balance + 1; // 投1元
//                 else if (coin == 3'b010) balance = balance + 2; // 投2元
//                 else if (coin == 3'b100) balance = balance + 5; // 投5元

//                 if (sel > 0) begin
//                     next_state = SELECT;
//                 end
//             end

//             SELECT: begin
//                 if (sel == 2'b01 && balance >= PRICE_A && num_goods[0] > 0) begin
//                     change = balance - PRICE_A;
//                     next_state = DISPENSE;
//                 end else if (sel == 2'b10 && balance >= PRICE_B && num_goods[1] > 0) begin
//                     change = balance - PRICE_B;
//                     next_state = DISPENSE;
//                 end else if (sel == 2'b11 && balance >= PRICE_C && num_goods[2] > 0) begin
//                     change = balance - PRICE_C;
//                     next_state = DISPENSE;
//                 end else if (num_goods[sel - 1] == 0) begin
//                     low_balance = 1; // 库存不足信号
//                     next_state = COIN;
//                 end else begin
//                     low_balance = 1; // 余额不足信号
//                     next_state = COIN;
//                 end
//             end

//             DISPENSE: begin
//                 dispense = 1; // 输出商品
//                 if (sel == 2'b01) num_goods[0] = num_goods[0] - 1; // 减少商品A库存
//                 else if (sel == 2'b10) num_goods[1] = num_goods[1] - 1; // 减少商品B库存
//                 else if (sel == 2'b11) num_goods[2] = num_goods[2] - 1; // 减少商品C库存
//                 next_state = FINISH;
//             end

//             FINISH: begin
//                 balance = 0; // 清零余额
//                 next_state = IDLE;
//             end

//             default: next_state = IDLE;
//         endcase
//     end

//     // ---------------------------------------------
//     // 库存查询功能
//     always @(posedge clk) begin
//         if (goods_num_query) begin
//             case (sel)
//                 2'b01: num_goods_disp = num_goods[0]; // 查询商品A库存
//                 2'b10: num_goods_disp = num_goods[1]; // 查询商品B库存
//                 2'b11: num_goods_disp = num_goods[2]; // 查询商品C库存
//                 default: num_goods_disp = 0;         // 无效查询返回0
//             endcase
//         end
//     end

// endmodule


//*************************************************************************************************

//last 2
// module vending_machine_mix1 (
//         input clk, rst,              // 时钟与复位信号
//         input [2:0] coin,            // 投币输入 (1元, 2元, 5元)
//         input [1:0] sel,             // 商品选择输入

//         //input goods_num_query;       // 库存查询信号

//         output reg dispense,         // 商品输出信号
//         output reg low_balance,      // 余额不足信号
//         output reg [4:0] change,     // 找零输出
//         output reg [4:0] balance     // 当前余额显示

//     );

//     // 状态定义
//     reg [4:0] state, next_state; // 定义状态和下一个状态的寄存器，使用4位宽度
//     reg [3:0] product_A_price, product_B_price, product_C_price; // 定义三个产品的价格寄存器，使用4位宽度
//     reg [23:0] timer; // 计时器，用于返回IDLE状态

//     // 初始化商品价格
//     initial begin
//         product_A_price = 4; // 商品A的价格是4
//         product_B_price = 6; // 商品B的价格是6
//         product_C_price = 8; // 商品C的价格是8
//     end

//     // 定义自动售货机的状态机状态

//     //IDLE (0001)：空闲状态，等待输入。
//     //COIN_IN (0010)：投币选择状态，接收用户的投币并记录余额。
//     //DISPENSE (0100)：发放商品状态，商品成功发放后重置余额。
//     //CHANGE (1000)：找零状态（此状态未实际用到，找零逻辑在 COIN_IN 中处理）。

//     localparam IDLE = 4'b0001, COIN_IN = 4'b0010, DISPENSE = 4'b0100, CHANGE = 4'b1000,REZERO = 4'b1111;


//     always @(posedge clk or posedge rst) begin
//         if (rst) begin
//             state <= IDLE; // 复位时，状态设置为IDLE
//             timer <= 24'b0; // 计时器清零
//         end
//         else begin
//             if (state == IDLE || state == COIN_IN) begin
//                 if (sel == 2'b00 && low_balance == 1) begin
//                     timer <= timer + 1;
//                     if (timer == 24'hFFFFFF)
//                         state <= CHANGE;//
//                 end
//                 else if (coin == 3'b000) begin
//                     timer <= timer + 1;
//                     if (timer == 24'hFFFFFF)
//                         state <= IDLE;
//                 end
//                 else begin
//                     timer <= 24'b0;
//                     state <= next_state;
//                 end
//             end
//             else begin
//                 state <= next_state;
//             end
//         end
//     end


//     // 状态机：组合逻辑
//     always @(*) begin
//         // 根据当前状态和输入选择下一个状态，并设置输出信号
//         next_state = state;
//         //dispense = 0;
//         // low_balance = 0;
//         // change = 0;

//         case (state)
//             IDLE: begin
//                 // 当前为闲置状态，如果有投币则转到投币状态
//                 if (coin > 0) // 如果投币金额大于0，进入投币状态
//                     next_state = COIN_IN;
//             end

//             COIN_IN: begin
//                 // 根据选择的商品判断是否可以购买，并计算找零
//                 case (sel)
//                     2'b01: begin // 选择商品A
//                         if (balance >= product_A_price) begin
//                             next_state = DISPENSE;
//                         end
//                         else begin
//                             next_state = CHANGE;
//                         end
//                     end
//                     2'b10: begin // 选择商品B
//                         if (balance >= product_B_price) begin
//                             next_state = DISPENSE;
//                         end
//                         else begin
//                             next_state = CHANGE;
//                         end
//                     end
//                     2'b11: begin // 选择商品C
//                         if (balance >= product_C_price) begin
//                             next_state = DISPENSE;
//                         end
//                         else begin
//                             next_state = CHANGE;
//                         end
//                     end
//                     default:
//                         next_state = IDLE;
//                 endcase
//             end

//             DISPENSE: begin
//                 next_state = IDLE;
//             end

//             CHANGE: begin
//                 next_state = IDLE;
//             end

//             default:
//                 next_state = IDLE; // 防止无效状态
//         endcase
//     end

//     always @(posedge clk or posedge rst) begin
//         if (rst) begin
//             balance <= 0;//复位时清零余额
//             low_balance <= 0;
//             change <= 0;
//             dispense <= 0;
//         end
//         else if (balance + (coin[0] * 1 + coin[1] * 2 + coin[2] * 5)>31) begin
//             //如果投币超出系统余额上限（最大余额为31元】
//             balance<=31;//设置余额为最大值
//         end
//         else begin
//             //根据投币金额更新余额
//             case (coin)
//                 3'b001:
//                     balance<=balance+1;//投入1元
//                 3'b010:
//                     balance<=balance+2;//投入2元
//                 3'b100:
//                     balance<=balance+5;//投入5元
//                 default:
//                     balance<=balance;//未投币时余额保持不变
//             endcase
//         end
//         if(sel!=2'b00 ) begin
//             //如果商品选择有效且余额充足，则进入选择商品状态
//             case (sel)
//                 2'b01: begin // 选择商品A
//                     if (balance >= product_A_price) begin
//                         dispense <= 1;
//                         change <= balance - product_A_price; // 计算找零
//                         low_balance <= 0;
//                     end
//                     else begin
//                         low_balance <= 1;    // 余额不足
//                         dispense <= 0;
//                         change <= balance;
//                     end
//                 end
//                 2'b10: begin // 选择商品B
//                     if (balance >= product_B_price) begin
//                         dispense <= 1;
//                         low_balance <= 0;
//                         change <= balance - product_B_price;
//                     end
//                     else begin
//                         low_balance <= 0;
//                         dispense <= 0;
//                         change <= balance;
//                     end
//                 end
//                 2'b11: begin // 选择商品C
//                     if (balance >= product_C_price) begin
//                         dispense <= 1;
//                         low_balance <= 0;
//                         change <= balance - product_C_price;
//                     end
//                     else begin
//                         low_balance <= 1;
//                         dispense <= 0;
//                         change <= balance;
//                     end
//                 end
//                 default: begin
//                     low_balance <= 1;
//                     change <= balance;
//                 end
//             endcase
//         end


//     end


//     // // 库存查询功能
//     // always @(posedge clk) begin
//     //     if (goods_num_query) begin
//     //         case(sel)
//     //             2'b01:
//     //                 num_goods_disp = num_goods[3:0];
//     //             2'b02:
//     //                 num_goods_disp = num_goods[7:4];
//     //             2'b11:
//     //                 num_goods_disp = num_goods[11:8];
//     //         endcase
//     //     end
//     // end

// endmodule

module vending_machine_mix1(
    // 输入信号
    input clk,                // 时钟信号，用于同步操作
    input rst,                // 复位信号，用于将机器状态恢复到初始状态
    input [2:0] coin,         // 投币输入，3位二进制表示不同面值的硬币（001: 1元； 010: 2元； 100: 5元）
    input [1:0] sel,          // 商品选择输入，2位二进制表示选择不同的商品

    // 输出信号
    output reg dispense,      // 商品输出信号，高电平表示正在出货
    output reg [4:0] balance, // 当前余额显示，5位二进制表示余额（最大31元）
    output reg [4:0] change,  // 找零输出，5位二进制表示找零金额
    output reg low_balance    // 余额不足信号，高电平表示余额不足
);

    // 商品价格参数
    parameter PRICE_A = 4;  // 商品A的价格是4元
    parameter PRICE_B = 6;  // 商品B的价格是6元
    parameter PRICE_C = 8;  // 商品C的价格是8元

    // 状态编码（使用独热码表示）
    parameter IDLE = 5'b00001;           // 空闲状态，等待用户操作
    parameter COLLECT = 5'b00010;        // 投币收集状态，正在接收用户投币
    parameter CHECK_BALANCE = 5'b00100;  // 余额检查状态，检查余额是否足够购买商品
    parameter REFUND = 5'b01000;         // 退款状态，退还用户余额
    parameter OUTPUT = 5'b10000;         // 出货状态，正在出货商品

    reg [4:0] state, next_state;    // 当前状态和下一个状态的寄存器
    reg [4:0] timer;                // 计时器，用于在COLLECT状态后返回IDLE状态

    // 时序逻辑部分，用于状态更新
    always @(posedge clk or posedge rst) begin
        if (rst) begin
            // 当复位信号有效时，将状态和下一个状态设置为IDLE
            state <= IDLE;
            next_state <= IDLE;
        end else begin
            // 否则，将当前状态更新为下一个状态
            state <= next_state;
        end
    end

    // 组合逻辑部分，用于状态转换逻辑
    always @(*) begin
        case (state)
            IDLE:
                // 在空闲状态，如果检测到有硬币投入，则进入COLLECT状态
                if (coin == 3'b001 || coin == 3'b010 || coin == 3'b100) begin
                    next_state = COLLECT;
                end else begin
                    next_state = IDLE;
                end
            COLLECT:
                // 在收集状态，如果计时器达到20，则进入REFUND状态
                if (timer >= 5'd20|| balance >= 31) begin
                    next_state = REFUND;
                end else if (sel) begin
                    // 如果有商品选择，则进入CHECK_BALANCE状态
                    next_state = CHECK_BALANCE;
                end else begin
                    next_state = COLLECT;
                end
            CHECK_BALANCE:
                // 在余额检查状态，根据选择和余额决定下一步状态
                case (sel)
                    2'b01:
                        if (balance < PRICE_A) begin
                            next_state = REFUND;
                        end else begin
                            next_state = OUTPUT;
                        end
                    2'b10:
                        if (balance < PRICE_B) begin
                            next_state = REFUND;
                        end else begin
                            next_state = OUTPUT;
                        end
                    2'b11:
                        if (balance < PRICE_C) begin
                            next_state = REFUND;
                        end else begin
                            next_state = OUTPUT;
                        end
                endcase
            REFUND:
                // 在退款状态，下一步状态为IDLE
                next_state = IDLE;
            OUTPUT:
                // 在出货状态，下一步状态为IDLE
                next_state = IDLE;
        endcase
    end


// 定义一个5位寄存器用于存储商品价格
reg [4:0] price;

// 商品处理及余额更新的时序逻辑块
// 该块在时钟信号上升沿或复位信号上升沿触发
always @(posedge clk or posedge rst) begin
    if (rst) begin
        // 如果复位信号有效，将所有输出和内部变量初始化为默认值
        dispense <= 1'd0; // 商品输出信号置为0，表示无商品出货
        balance <= 5'd0; // 当前余额显示置为0
        change <= 5'd0; // 找零输出置为0
        low_balance <= 1'd0; // 余额不足标志置为0
        timer <= 5'd0; // 计时器置为0
        price <= 5'd0; // 商品价格置为0
    end
    else begin
        // 根据当前状态执行相应的操作
        case (state)
            IDLE: begin
                // 空闲状态：初始化输出和内部变量
                change <= 5'd0; // 找零置为0
                balance <= 5'd0; // 余额置为0
                dispense <= 0; // 商品输出信号置为0
                low_balance <= 0; // 余额不足标志置为0
                price <= 5'd0; // 商品价格置为0
                timer <= 5'd0; // 计时器置为0

                // 根据投入的硬币更新余额
                if (coin == 3'b001) // 如果投入1元
                    balance <= balance + 1; // 余额加1
                else if (coin == 3'b010) // 如果投入2元
                    balance <= balance + 2; // 余额加2
                else if (coin == 3'b100) // 如果投入5元
                    balance <= balance + 5; // 余额加5
                else
                    balance <= balance; // 否则余额保持不变
            end
            COLLECT: begin
                // 收集状态：增加计时器计数，更新余额和商品价格
                timer <= timer + 1; // 计时器加1

                // 根据投入的硬币更新余额，确保余额不超过最大值31
                case (coin)
                    3'b001: // 如果投入1元
                        balance <= (balance + 1 > 31) ? 31 : (balance + 1); // 余额加1，不超过31
                    3'b010: // 如果投入2元
                        balance <= (balance + 2 > 31) ? 31 : (balance + 2); // 余额加2，不超过31
                    3'b100: // 如果投入5元
                        balance <= (balance + 5 > 31) ? 31 : (balance + 5); // 余额加5，不超过31
                    default:
                        balance <= balance; // 否则余额保持不变
                endcase

                // 根据商品选择设置商品价格
                case (sel)
                    2'b01: // 如果选择商品1
                        price <= 5'd4; // 设置价格为4
                    2'b10: // 如果选择商品2
                        price <= 5'd6; // 设置价格为6
                    2'b11: // 如果选择商品3
                        price <= 5'd8; // 设置价格为8
                    default:
                        price <= 5'd0; // 否则价格置为0
                endcase
            end
            CHECK_BALANCE: begin
                // 余额检查状态：当前状态下不执行任何操作
                // 此状态可能用于等待其他操作或检查
            end
            REFUND: begin
                // 退款状态：设置找零为当前余额，重置其他输出信号
                change <= balance; // 找零设置为当前余额
                dispense <= 0; // 商品输出信号置为0
                balance <= 5'd0; // 余额置为0
                low_balance <= 1; // 余额不足标志置为1
            end
            OUTPUT: begin
                // 出货状态：计算找零，设置出货信号，重置余额和余额不足信号
                change <= balance - price; // 计算找零
                dispense <= 1; // 商品输出信号置为1，表示出货
                balance <= 5'd0; // 余额置为0
                low_balance <= 0; // 余额不足标志置为0
            end
        endcase
    end
end

endmodule




//*************************************************************************************************


// module vending_machine(
//     input clk, // 时钟信号
//     input rst, // 重置信号
//     input [1:0] key, // 投币信号
//     input [2:0] sel_goods, // 商品选择信号
//     input deal, // 确认交易信号
//     output reg [7:0] balance, // 当前余额状态
//     output reg insufficient_funds, // 余额不足信号
//     output reg dispense, // 出货信号
//     output reg [15:0] change // 找零金额
// );

// // 状态编码：独热码
// localparam IDLE = 4'b0001;
// localparam COIN = 4'b0010;
// localparam SELECT = 4'b0100;
// localparam DISPENSE = 4'b1000;

// // 商品价格
// localparam PRICE_A = 8'd20; // 商品A价格 20
// localparam PRICE_B = 8'd35; // 商品B价格 35
// localparam PRICE_C = 8'd30; // 商品C价格 30

// // 状态寄存器
// reg [3:0] state, next_state;
// reg [7:0] current_price; // 当前选择的商品价格

// // 投币金额
// reg [3:0] num_5_jiao; // 投入5角数量
// reg [3:0] num_1_yuan; // 投入1元数量

// // 余额计算
// always @(posedge clk or posedge rst) begin
//     if (rst) begin
//         num_5_jiao <= 0;
//         num_1_yuan <= 0;
//         balance <= 0;
//     end else begin
//         if (key[0]) // 投入5角
//             num_5_jiao <= num_5_jiao + 1;
//         if (key[1]) // 投入1元
//             num_1_yuan <= num_1_yuan + 1;

//         // 计算余额（角为单位）
//         balance <= (num_1_yuan * 10) + (num_5_jiao * 5);
//     end
// end

// // 状态转移逻辑
// always @(posedge clk or posedge rst) begin
//     if (rst) begin
//         state <= IDLE;
//     end else begin
//         state <= next_state;
//     end
// end

// always @(*) begin
//     // 默认值
//     next_state = state;
//     insufficient_funds = 0;
//     dispense = 0;
//     change = 0;

//     case (state)
//         IDLE: begin
//             if (key[0] || key[1])
//                 next_state = COIN;
//         end

//         COIN: begin
//             if (sel_goods != 3'b000) begin
//                 // 设置当前选择商品的价格
//                 case (sel_goods)
//                     3'b001: current_price = PRICE_A;
//                     3'b010: current_price = PRICE_B;
//                     3'b100: current_price = PRICE_C;
//                     default: current_price = 0;
//                 endcase
//                 next_state = SELECT;
//             end
//         end

//         SELECT: begin
//             if (deal) begin
//                 if (balance >= current_price) begin
//                     // 出货并找零
//                     change = balance - current_price;
//                     dispense = 1;
//                     next_state = DISPENSE;
//                 end else begin
//                     // 余额不足
//                     insufficient_funds = 1;
//                     next_state = IDLE;
//                 end
//             end
//         end

//         DISPENSE: begin
//             // 出货完成后返回IDLE状态
//             next_state = IDLE;
//         end

//         default: next_state = IDLE;
//     endcase
// end

// endmodule

